AngularJS 製アプリで jQuery を使いたい
本記事で使用している AngularJS のバージョン
1.2.16
angular.element
先日紹介した ng Global APIs の中に angular.element というメソッドが用意されています。
このメソッドは、デフォルトでは "jQuery lite" または "jqLite" と呼ばれる AngularJS が提供する jQuery のサブセット ( 軽量版 jQuery ) オブジェクトを返しますが、ドキュメントを読む限り制限が多く、困ることが少なくありません。
どのくらい制限されているかというと、、、
https://docs.angularjs.org/api/ng/function/angular.element より
addClass()
after()
append()
attr()
bind()
- Does not support namespaces, selectors or eventDatachildren()
- Does not support selectorsclone()
contents()
css()
data()
empty()
eq()
find()
- Limited to lookups by tag namehasClass()
html()
next()
- Does not support selectorson()
- Does not support namespaces, selectors or eventDataoff()
- Does not support namespaces or selectorsone()
- Does not support namespaces or selectorsparent()
- Does not support selectorsprepend()
prop()
ready()
remove()
removeAttr()
removeClass()
removeData()
replaceWith()
text()
toggleClass()
triggerHandler()
- Passes a dummy event object to handlers.unbind()
- Does not support namespacesval()
wrap()
アプリケーションの仕様によっては、たいへん困る可能性があります。
jqLite を jQuery で上書きする
おそらく開発者も困ると考えていたのでしょうか、逃げ道を用意してくれています。
angular.js
function bindJQuery() { // bind to jQuery if present; jQuery = window.jQuery; // reset to jQuery or default to us. if (jQuery) { jqLite = jQuery; extend(jQuery.fn, { scope: JQLitePrototype.scope, isolateScope: JQLitePrototype.isolateScope, controller: JQLitePrototype.controller, injector: JQLitePrototype.injector, inheritedData: JQLitePrototype.inheritedData }); // Method signature: // jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) jqLitePatchJQueryRemove('remove', true, true, false); jqLitePatchJQueryRemove('empty', false, false, false); jqLitePatchJQueryRemove('html', false, false, true); } else { jqLite = JQLite; } angular.element = jqLite; }
上記 bindJQuery() メソッドは、angular.js 実行時に 1 度だけ呼ばれる初期化メソッドです。つまり、このメソッドが実行される前に window.jQuery が初期化されていれば良いので…
<script src="jquery.js"></script> <script src="angular.js"></script>
と書いておけば、jqLite は jQuery に上書きされるので OK というわけです。ただし、angular.js 内部で .on() や .off() メソッドを使用しているために 1.7.0 以上のバージョンの jQuery を使用する必要があります。
主にディレクティブ内で使う?
AngularJS では、DOM の参照は常に jQuery または jqLite でラップされ、素の DOM を参照することはありません。ディレクティブ内でもそのルールは守られます。
公式ドキュメントのディレクティブのサンプルでも、しっかり jqLite が使われてます。
- https://docs.angularjs.org/guide/directive#creating-a-directive-that-manipulates-the-dom
- https://docs.angularjs.org/guide/directive#creating-a-directive-that-adds-event-listeners
サンプル
前述の jQuery 上書きサンプルを用意したので貼り付けておきます。jQuery の読み込み行を削除すると、エラーが発生することが確認できるはずです。
絞め
AngularJS が標準で jqLite を採用しているのは、できる限り軽量なフレームワークでありたいという思想があるからだと思います。もちろん、jQuery を使えば大抵の問題はクリアできますが、本当に困るまで我慢した方がエコだと思いますし、なんというか硬派でカッコいい気がするので、それなりに検討してから方針を決めればよいのではないでしょうか。